package com.sky.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.api.cart.CartFeignService;
import com.sky.api.member.MemberFeignService;
import com.sky.api.product.ProductFeignService;
import com.sky.api.ware.WareFeignService;
import com.sky.config.LoginUserInterceptor;
import com.sky.constant.*;
import com.sky.domain.OmsOrder;
import com.sky.domain.OmsOrderItem;
import com.sky.dto.SkuStockVO;
import com.sky.dto.member.UmsMemberVO;
import com.sky.exception.BizException;
import com.sky.service.OmsOrderItemService;
import com.sky.service.OmsOrderService;
import com.sky.mapper.OmsOrderMapper;
import com.sky.to.member.MemberReceiveAddressTo;
import com.sky.to.order.OmsOrderTo;
import com.sky.to.product.SpuInfoTo;
import com.sky.to.ware.SkuStockTo;
import com.sky.to.ware.StockTo;
import com.sky.utils.R;
import com.sky.utils.StringUtils;
import com.sky.vo.*;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author Administrator
* @description 针对表【oms_order(订单)】的数据库操作Service实现
* @createDate 2024-06-30 16:46:10
*/
@Service
public class OmsOrderServiceImpl extends ServiceImpl<OmsOrderMapper, OmsOrder> implements OmsOrderService{

    @Resource
    private MemberFeignService memberFeignService;
    @Resource
    private CartFeignService cartFeignService;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;
    @Resource
    private WareFeignService wareFeignService;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private OmsOrderItemService omsOrderItemService;
    @Resource
    private ProductFeignService productFeignService;

    /**
     * @author zhl
     * @description 获取当前登录用户的商品购物车结算信息
     * @date 2024/8/29 14:39
     */
    @Override
    public SettlementVo getUserSettlement() throws Exception {
        SettlementVo settlementVo = new SettlementVo();

        // 获取当前登录用户
        UmsMemberVO umsMemberVO = LoginUserInterceptor.threadLocal.get();

        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            // 1、收货地址列表
            R<List<String>> memberAddress = memberFeignService.getAddressByMemberId(umsMemberVO.getId());
            if (memberAddress.getCode() == 0) {
                List<String> addressList = memberAddress.getData();
                List<MemberReceiveAddressVo> addressVoList = new ArrayList<>();
                if (StringUtils.isNotEmpty(addressList)) {
                    for (String s : addressList) {
                        MemberReceiveAddressVo memberReceiveAddressVo = JSON.parseObject(s, MemberReceiveAddressVo.class);
                        addressVoList.add(memberReceiveAddressVo);
                    }
                }
                settlementVo.setAddressVoList(addressVoList);
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            // 2、购物车列表
            R<List<String>> listR = cartFeignService.getCartByUserId(umsMemberVO.getId());
            if (listR.getCode() == 0) {
                List<String> cartList = listR.getData();
                if (StringUtils.isNotEmpty(cartList)) {
                    List<OrderItemVo> cartVoList = cartList.stream().map(cart -> JSON.parseObject(cart, OrderItemVo.class)).collect(Collectors.toList());
                    settlementVo.setCartVoList(cartVoList);

                    // 获取商品总价
                    BigDecimal totalPrice = cartVoList.stream().map(OrderItemVo::getTotalPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
                    settlementVo.setTotalPrice(totalPrice);
                    settlementVo.setPayPrice(totalPrice);

                    // 商品数量
                    Integer count = cartVoList.stream().map(OrderItemVo::getCount).collect(Collectors.summingInt(Integer::intValue));
                    settlementVo.setSkuCount(count);
                }
            }
        }, threadPoolExecutor).thenRunAsync(()->{
            List<OrderItemVo> cartVoList = settlementVo.getCartVoList();
            List<Long> list = cartVoList.stream().map(OrderItemVo::getSkuId).collect(Collectors.toList());
            R<List<SkuStockVO>> skuStock = wareFeignService.getSkuStock(list);
            if (skuStock.getCode() == 0) {
                List<SkuStockVO> skuStockVOList = skuStock.getData();
                if (StringUtils.isNotEmpty(skuStockVOList)) {
                    Map<Long, Boolean> map = skuStockVOList.stream().collect(Collectors.toMap(SkuStockVO::getSkuId, SkuStockVO::getHasStock));
                    cartVoList.forEach(orderItemVo -> orderItemVo.setHasStock(map.get(orderItemVo.getSkuId())));
                    settlementVo.setCartVoList(cartVoList);
                }
            }
        },threadPoolExecutor);

        // 3、查询用户的积分
        settlementVo.setIntegration(umsMemberVO.getIntegration());

        CompletableFuture.allOf(addressFuture, cartFuture).get();

        // 4、订单token
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX + umsMemberVO.getId().toString(),token,30, TimeUnit.MINUTES);
        settlementVo.setOrderToken(token);

        return settlementVo;
    }

    /**
     * @author zhl
     * @description 生成当前登录用户的商品订单信息
     * @date 2024/8/29 14:39
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitResponseVo submitOrder(OrderSubmitVo orderSubmitVo) throws Exception{
        OrderSubmitResponseVo responseVo = new OrderSubmitResponseVo();

        // 获取当前登录用户
        UmsMemberVO umsMemberVO = LoginUserInterceptor.threadLocal.get();
        // 使用lua脚本加锁
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(OrderConstant.ORDER_REDIS_SCRIPT);
        String key = OrderConstant.ORDER_TOKEN_PREFIX + umsMemberVO.getId();
        Long execute = (Long) redisTemplate.execute(script, Arrays.asList(key), orderSubmitVo.getOrderToken());
        if (1 == execute){
            // 验证token成功
            OmsOrder order = new OmsOrder();
            order.setMemberId(umsMemberVO.getId());
            order.setCreateTime(new Date());
            order.setMemberUsername(umsMemberVO.getUsername());
            order.setPayType(PayType.ALI_PAY.getCode());
            order.setStatus(OrderStatus.OBLIGATION.getCode());
            order.setSourceType(OrderSourceType.PC.getCode());

            // 生成订单号
            String orderSn = IdUtil.getSnowflake().nextIdStr().toString();
            order.setOrderSn(orderSn);

            // 生成商品订单的邮寄信息
            buildAddress(orderSubmitVo, order);

            // 生成商品订单的订单列表项数据
            List<OmsOrderItem> omsOrderItems = buildOrderItems(umsMemberVO, orderSn);

            // 计算订单金额
            calculateAmount(omsOrderItems, order);

            // 验价（前端传的价格值与后端计算出来的价格值误差不能超过一个值）
            if (Math.abs(orderSubmitVo.getPayPrice().subtract(order.getPayAmount()).doubleValue()) > OrderConstant.ERROR_PRICE){
                responseVo.setCode(OrderSubmitCode.ERROR_PRICE.getCode());
            } else {
                // 保存订单列表项
                omsOrderItemService.saveBatch(omsOrderItems);
                // 保存订单信息
                baseMapper.insert(order);

                order.setOmsOrderItems(omsOrderItems);
            }

            // 锁库存
            List<SkuStockTo> skuStockList = omsOrderItems.stream().map(data -> {
                SkuStockTo skuStockTo = new SkuStockTo();
                skuStockTo.setSkuId(data.getSkuId());
                skuStockTo.setNum(data.getSkuQuantity());
                return skuStockTo;
            }).collect(Collectors.toList());
            StockTo stockTo = new StockTo(orderSn, skuStockList);
            R<Boolean> booleanR = wareFeignService.lockStock(stockTo);
            if (booleanR.getCode() != 0){
                responseVo.setCode(OrderSubmitCode.ERROR_STOCK.getCode());
            }
            responseVo.setOmsOrder(order);
            responseVo.setCode(OrderSubmitCode.SUCCESS.getCode());
        } else {
            // 验证token失败
            responseVo.setCode(OrderSubmitCode.ERROR_TOKEN.getCode());
        }
        int i = 1/0;
        return responseVo;
    }

    /**
     * @author zhl
     * @description 计算订单金额
     * @date 2024/8/29 14:44
     */
    private static void calculateAmount(List<OmsOrderItem> omsOrderItems, OmsOrder order) {
        BigDecimal totalAmount = omsOrderItems.stream().map(OmsOrderItem::getRealAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        order.setTotalAmount(totalAmount);
        BigDecimal payAmount = totalAmount.add(order.getFreightAmount());
        order.setPayAmount(payAmount);

        order.setPromotionAmount(BigDecimal.ZERO);
        order.setCouponAmount(BigDecimal.ZERO);
        order.setIntegrationAmount(BigDecimal.ZERO);

        // 总积分
        Integer integration = omsOrderItems.stream().map(OmsOrderItem::getGiftIntegration).reduce(0, Integer::sum);
        order.setIntegration(integration);
        // 总成长值
        Integer giftGrowth = omsOrderItems.stream().map(OmsOrderItem::getGiftGrowth).reduce(0, Integer::sum);
        order.setGrowth(giftGrowth);
    }

    /**
     * @author zhl
     * @description 生成商品订单的订单列表项数据
     * @date 2024/8/29 14:44
     */
    private List<OmsOrderItem> buildOrderItems(UmsMemberVO umsMemberVO, String orderSn) {
        R<List<String>> listR = cartFeignService.getCartByUserId(umsMemberVO.getId());
        if (listR.getCode() == 0) {
            List<String> cartList = listR.getData();
            if (StringUtils.isNotEmpty(cartList)) {
                List<OrderItemVo> cartVoList = cartList.stream().map(cart -> JSON.parseObject(cart, OrderItemVo.class)).collect(Collectors.toList());
                List<OmsOrderItem> itemList = cartVoList.stream().map(orderItemVo -> {
                    OmsOrderItem orderItem = buildAddressOrderItem(orderSn,orderItemVo);
                    return orderItem;
                }).collect(Collectors.toList());
                return itemList;
            }
        }
        return null;
    }

    /**
     * @author zhl
     * @description 生成商品订单的订单列表项数据
     * @date 2024/8/29 14:44
     */
    private OmsOrderItem buildAddressOrderItem(String orderSn, OrderItemVo orderItemVo) {
        OmsOrderItem orderItem = new OmsOrderItem();
        orderItem.setOrderSn(orderSn);
        // 品牌信息
        R<SpuInfoTo> spuInfoToR = productFeignService.getSpuBySkuId(orderItemVo.getSkuId());
        if (spuInfoToR.getCode() == 0) {
            SpuInfoTo spuInfoTo = spuInfoToR.getData();
            orderItem.setSpuId(spuInfoTo.getId());
            orderItem.setSpuName(spuInfoTo.getSpuName());
            orderItem.setSpuPic(spuInfoTo.getSpuPic());
            orderItem.setSpuBrand(spuInfoTo.getSpuBrand());
            orderItem.setCategoryId(spuInfoTo.getCatalogId());
        }
        // 商品信息
        orderItem.setSkuId(orderItemVo.getSkuId());
        orderItem.setSkuName(orderItemVo.getSkuName());
        orderItem.setSkuPic(orderItemVo.getImage());
        orderItem.setSkuQuantity(orderItemVo.getCount());
        orderItem.setSkuPrice(orderItemVo.getPrice());
        orderItem.setSkuAttrsVals(StringUtils.join(orderItemVo.getSkuAttr(), ","));
        // 优惠价格
        orderItem.setPromotionAmount(BigDecimal.ZERO);
        orderItem.setCouponAmount(BigDecimal.ZERO);
        orderItem.setIntegrationAmount(BigDecimal.ZERO);
        orderItem.setRealAmount(orderItemVo.getTotalPrice());
        // 积分信息
        orderItem.setGiftIntegration(orderItemVo.getTotalPrice().intValue());
        orderItem.setGiftGrowth(orderItemVo.getTotalPrice().intValue());
        return orderItem;
    }

    /**
     * @author zhl
     * @description 生成商品订单的邮寄信息
     * @date 2024/8/29 14:39
     */
    private void buildAddress(OrderSubmitVo orderSubmitVo, OmsOrder order) throws Exception {
        // 查询邮寄信息
        R<MemberReceiveAddressTo> address = wareFeignService.getFreight(orderSubmitVo.getAddrId());
        if (address.getCode() == 0){
            MemberReceiveAddressTo memberReceiveAddressTo = address.getData();
            order.setFreightAmount(memberReceiveAddressTo.getFreight());
            order.setReceiverName(memberReceiveAddressTo.getName());
            order.setReceiverPhone(memberReceiveAddressTo.getPhone());
            order.setReceiverPostCode(memberReceiveAddressTo.getPostCode());
            order.setReceiverProvince(memberReceiveAddressTo.getProvince());
            order.setReceiverCity(memberReceiveAddressTo.getCity());
            order.setReceiverRegion(memberReceiveAddressTo.getRegion());
            order.setReceiverDetailAddress(memberReceiveAddressTo.getDetailAddress());
        } else {
            throw new BizException(OrderSubmitCode.ERROR_ADDRESS.getMsg());
        }
    }


    /**
     * @param orderSn
     * @author zhl
     * @description 根据订单号查询订单信息
     * @date 2024/8/29 14:39
     */
    @Override
    public OmsOrderTo getInfoByOrderSn(String orderSn) {
        OmsOrder omsOrder = baseMapper.selectOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSn));
        OmsOrderTo omsOrderTo = new OmsOrderTo();
        BeanUtils.copyProperties(omsOrder, omsOrderTo);
        return omsOrderTo;
    }
}




